﻿using System;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Windows.Input;
using Peter.Common;
using Peter.Common.MainMenu;
using Peter.Sdw.Data;
using Peter.Sdw.Properties;

namespace Peter.Sdw.Logic
{
   /// <summary>
   /// View model for a sub book.
   /// </summary>
   public class SubBookModel : BaseModel
   {
      private bool m_Hide;
      private int m_Order;
      private int m_TermId;
      private string m_Alias;
      private string m_TermName;
      private AddListModel m_AddContent;
      private RelayCommand m_CmdAddChapters;
      private ChapterModel m_SelectedChapter;

      /// <summary>
      /// Initializes a new sub book view model.
      /// </summary>
      /// <param name="version">The parent version.</param>
      public SubBookModel (VersionModel version)
         : base (version)
      {
         this.Version = version;
      }

      /// <summary>
      /// Gets the parent version.
      /// </summary>
      public VersionModel Version { get; private set; }

      #region Sub Book Data

      /// <summary>
      /// Gets or Sets the order.
      /// </summary>
      public int Order
      {
         get { return this.m_Order; }
         set
         {
            if (this.m_Order != value) {
               this.m_Order = value;
               this.RaisePropertyChanged ("Order");
               this.Edit ();
            }
         }
      }

      /// <summary>
      /// Gets or Sets the alias for the sub book.
      /// </summary>
      public string Alias
      {
         get { return this.m_Alias; }
         set
         {
            if (this.m_Alias != value) {
               this.m_Alias = value;
               this.RaisePropertyChanged ("Alias");
               this.Edit ();
            }
         }
      }

      /// <summary>
      /// Gets or Sets the associated term's id.
      /// </summary>
      public int TermId
      {
         get { return this.m_TermId; }
         set
         {
            if (this.m_TermId != value) {
               this.m_TermId = value;
               this.RaisePropertyChanged ("TermId");
               this.Edit ();
            }
         }
      }

      /// <summary>
      /// Gets or Sets the term name.
      /// </summary>
      public string TermName
      {
         get { return this.m_TermName; }
         set
         {
            if (this.m_TermName != value) {
               this.m_TermName = value;
               this.RaisePropertyChanged ("TermName");
            }
         }
      }

      /// <summary>
      /// Gets or Sets if this should be hidden or not.
      /// </summary>
      public bool Hide
      {
         get { return this.m_Hide; }
         set
         {
            if (this.m_Hide != value) {
               this.m_Hide = value;
               this.RaisePropertyChanged ("Hide");
               this.Edit ();
            }
         }
      }

      #endregion

      /// <summary>
      /// Gets the command used to add chapters.
      /// </summary>
      public ICommand AddChaptersCommand
      {
         get { return this.m_CmdAddChapters ?? (this.m_CmdAddChapters = new RelayCommand (this.OnAddChapters, this.CanAddChapters)); }
      }

      /// <summary>
      /// Gets or Sets the selected chapter.
      /// </summary>
      public ChapterModel SelectedChapter
      {
         get { return this.m_SelectedChapter; }
         set
         {
            this.m_SelectedChapter = value;
            if (this.m_SelectedChapter != null)
               this.m_SelectedChapter.GetPassages ();
            this.RaisePropertyChanged ("SelectedChapter");
         }
      }

      /// <summary>
      /// Checks to see if this item can be deleted or not.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      protected override bool CanDelete (object obj)
      {
         return this.SelectedChapter != null;
      }

      /// <summary>
      /// Checks to see if the command can execute.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      /// <returns>True if the command can execute, otherwise false.</returns>
      private bool CanAddChapters (object obj)
      {
         return this.Id > 0;
      }

      /// <summary>
      /// Adds the current list of chapters.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      private void OnAddChapters (object obj)
      {
         var editor = this.Version.Book.Peter.NewFile ();
         editor.Title = "Add Chapters";
         editor.Icon = MainMenuIcon.Notebook;
         if (this.m_AddContent == null) {
            this.m_AddContent = new AddListModel {
               Message = { Message = "Create the list of Chapters to add. Place each chapter on a new line." }
            };
         }
         this.m_AddContent.Editor = editor;
         this.m_AddContent.Add.AddRequested += this.OnAddChapterList;
         editor.TopContent = this.m_AddContent.Message;
         editor.RightContent = this.m_AddContent.Range;
         editor.BottomContent = this.m_AddContent.Add;
      }

      /// <summary>
      /// Occurs when the user adds the given content.
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void OnAddChapterList (object sender, EventArgs e)
      {
         this.IsLoading = true;
         this.m_AddContent.Add.AddRequested -= this.OnAddChapterList;
         var list = this.m_AddContent.Editor.Text;
         var parameters = new NameValueCollection {
            {Constants.REQUEST_TOKEN, WebQueue.Instance.RequestToken},
            {"id", this.Id.ToString (CultureInfo.InvariantCulture)},
            {"list", list},
         };
         WebQueue.Instance.WebPostComplete += this.OnPostCompleted;
         WebQueue.Instance.Post (Constants.URL_CREATE_CHAPTERS, parameters);
         this.Version.Book.Peter.CloseDocument (this.m_AddContent.Editor);
         this.m_AddContent.Editor = null;
      }

      /// <summary>
      /// Gets the list of version from the server.
      /// </summary>
      public void GetChapters ()
      {
         this.IsLoading = true;
         this.Children.Clear ();
         WebQueue.Instance.WebGetComplete += this.OnGetCompleted;
         WebQueue.Instance.Get (string.Format (Constants.URL_CHAPTER_LIST, this.Id));
      }

      /// <summary>
      /// Posts the edit data to the server.
      /// </summary>
      private void Edit ()
      {
         if (this.TermId == 0 || !this.OkToUpdate) return;
         var parameters = new NameValueCollection
         {
            {Constants.REQUEST_TOKEN, WebQueue.Instance.RequestToken},
            {"id", this.Id.ToString (CultureInfo.InvariantCulture)},
            {"alias", this.Alias},
            {"visible", Convert.ToString(!this.Hide)},
            {"termId", this.TermId.ToString (CultureInfo.InvariantCulture)}
         };
         WebQueue.Instance.WebPostComplete += this.OnPostCompleted;
         WebQueue.Instance.Post (Constants.URL_EDIT_SUB_BOOK, parameters);
      }

      /// <summary>
      /// Adds the given chapters to the current list.
      /// </summary>
      /// <param name="response">The server response.</param>
      private void AddChapters (dynamic response)
      {
         foreach (var chapter in response.chapters) {
            bool isPara = chapter.isparagraphs;
            this.Children.Add (new ChapterModel (this) {
               Id = chapter.id,
               Name = chapter.name,
               Hide = chapter.hide,
               Order = chapter.order,
               Number = chapter.number,
               Header = chapter.header,
               Footer = chapter.footer,
               ChapterId = chapter.chapterid,
               Mode = (isPara ? Constants.PARAGRAPH : Constants.VERSE)
            });
         }
         foreach (var chapter in this.Children.Cast <ChapterModel> ()) {
            chapter.OkToUpdate = true;
         }
      }

      /// <summary>
      /// Loads any children nodes.
      /// </summary>
      protected override void LoadChildren ()
      {
         this.IsSelected = true;
         this.GetChapters ();
      }

      /// <summary>
      /// Occurs when a web request is completed.
      /// </summary>
      /// <param name="sender">WebQueue.</param>
      /// <param name="e">WebRequestEventArgs</param>
      private void OnGetCompleted (object sender, WebRequestEventArgs e)
      {
         try {
            if (e.Url == string.Format (Constants.URL_CHAPTER_LIST, this.Id)) {
               WebQueue.Instance.WebGetComplete -= this.OnGetCompleted;
               if (e.Response.status == Constants.SUCCESS) {
                  this.AddChapters (e.Response);
               }
               this.IsLoading = false;
            }
         } catch (Exception ex) {
            Console.Error.WriteLine (ex.Message);
         }
      }

      /// <summary>
      /// Occurs when a web post request is completed.
      /// </summary>
      /// <param name="sender">WebQueue.</param>
      /// <param name="e">WebRequestEventArgs</param>
      private void OnPostCompleted (object sender, WebRequestEventArgs e)
      {
         if (e.Url == Constants.URL_EDIT_SUB_BOOK) {
            WebQueue.Instance.WebPostComplete -= this.OnPostCompleted;
            if (e.Response.status == Constants.SUCCESS)
               Console.WriteLine (Resources.Edit_successful);
         } else if (e.Url == Constants.URL_CREATE_CHAPTERS) {
            WebQueue.Instance.WebPostComplete -= this.OnPostCompleted;
            if (e.Response.status == Constants.SUCCESS) {
               Console.WriteLine (Resources.Subbooks_Created);
               this.AddChapters (e.Response);
            }
            this.IsLoading = false;
         }
      }
   }
}
